package org.dyndns.opendemogroup.optimizer.problems;

import java.util.Random;

import org.dyndns.opendemogroup.optimizer.ArrayUtil;
import org.dyndns.opendemogroup.optimizer.ICustomCoding;
import org.dyndns.opendemogroup.optimizer.IOptimizationProblem;
import org.dyndns.opendemogroup.optimizer.Member;

/**
 * Implemented based on specification in the second assignment.
 */
public class LowAutocorrelationBinarySequence implements IOptimizationProblem,
		ICustomCoding
{

	private int memberSize;

	protected double[] s;

	public LowAutocorrelationBinarySequence ( int memberSize )
	{
		this.memberSize = memberSize;
		s = new double[memberSize];
	}

	/**
	 * @see IOptimizationProblem#computeFitness(Random)
	 */
	public double computeFitness ( Random randomSource )
	{
		int h = 0;
		for ( int g = 1; g <= memberSize - 1; g++ )
		{
			final int c_of_g = compute_c_of_g ( g );
			h += ( c_of_g * c_of_g );
		}
		double fitness = h;
		return fitness;
	}

	private int compute_c_of_g ( int g )
	{
		int c = 0;
		for ( int i = 0; i < memberSize - g; i++ )
		{
			c += ( s[i] * s[i + g] );
		}
		return c;
	}

	/**
	 * @see IOptimizationProblem#getGeneRange()
	 */
	public int getGeneRange ( )
	{
		return 1;
	}

	/**
	 * @see IOptimizationProblem#getMemberSize()
	 */
	public int getMemberSize ( )
	{
		return memberSize;
	}

	/**
	 * @see IOptimizationProblem#isCombinatorialOptimization()
	 */
	public boolean isCombinatorialOptimization ( )
	{
		return false;
	}

	/**
	 * @see IOptimizationProblem#isMaximizing()
	 */
	public boolean isMaximizing ( )
	{
		return false;
	}

	public void decodeFrom ( Member source )
	{
		ArrayUtil.copy ( source.genome, s, 0, memberSize - 1 );
		// { adjust values to -1 and +1
		for ( int i = 0; i < memberSize; i++ )
		{
			if ( 0 == s[i] )
			{
				s[i] = -1;
			}
		}
		// }
	}

	public void encodeTo ( Member target )
	{
		ArrayUtil.copy ( s, target.genome, 0, memberSize - 1 );
		// { adjust values to 0 and 1
		for ( int i = 0; i < memberSize; i++ )
		{
			if ( -1 == target.genome[i] )
			{
				target.genome[i] = 0;
			}
		}
		// }
	}

	public void decodeFrom ( String source )
	{
		int d = 0;
		boolean isPositive = true;
		for ( int i = 0; i < source.length ( ); i++ )
		{
			String c = String.valueOf ( source.charAt ( i ) );
			int runLength = Integer.parseInt ( c, 10 );
			for ( int j = 0; j < runLength; j++ )
			{
				s[d] = isPositive ? 1 : -1;
				d++;
			}
			isPositive = !isPositive;
		}
	}

	public boolean makeValid ( )
	{
		// do nothing on purpose
		return false;
	}
}
